package com.ticket.sass.provider.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.Map;

/**
 * @author ywb
 * @date 2023-02-23 13:59
 */

@Slf4j
@Component
public class JwtUtil {
    
    public static final String TOKEN_PREFIX = "Bearer ";
    public static final String TOKEN_HEADER = "Authorization";
    public static final long EXPIRATION_TIME = 864000; // 1 day
    public static final String VALID_TOKEN_CACHE_KEY = "ticket-admin-token-uid:%s";
    
    @Value("${config.jwt.secret:32e6436f6kd6540973c011a6628664dd}")
    private String secret;
    
    public TokenModel createToken(Long adminId, String account) {
        Instant expires = LocalDateTime.now().plusDays(EXPIRATION_TIME).toInstant(ZoneOffset.of("+8"));
        String token = JWT.create()
            .withAudience(adminId.toString())
            .withSubject(account)
            .withExpiresAt(Date.from(expires))
            .sign(Algorithm.HMAC512(secret));
        return new TokenModel(expires.getEpochSecond(), TOKEN_PREFIX + token);
    }
    
    public String getAccount(HttpServletRequest request) {
        return this.getClaim(request, "sub");
    }
    
    public Integer getAdminId(HttpServletRequest request) {
        String aud = this.getClaim(request, "aud");
        return StringUtils.isEmpty(aud) ? null : Integer.parseInt(aud);
    }

    
    public Map<String, Claim> getClaimMap(HttpServletRequest request) {
        return this.verify(this.getAuthToken(request)).getClaims();
    }
    
    public String getClaim(HttpServletRequest request, String name) {
        DecodedJWT jwt = this.verify(this.getAuthToken(request));
        Claim claim = jwt.getClaim(name);
        return claim == null ? null : claim.asString();
    }
    
    public DecodedJWT verify(String token) {
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC512(secret)).build();
        return jwtVerifier.verify(token);
    }
    
    public String getAuthToken(HttpServletRequest request) {
        String authToken = request.getHeader(TOKEN_HEADER);
        if (authToken == null) {
            return "";
        }
        if (!authToken.startsWith(TOKEN_PREFIX)) {
            return "";
        }
        return authToken.substring(TOKEN_PREFIX.length());
    }
    
    public String validTokenCacheKey(Object uid) {
        return String.format(VALID_TOKEN_CACHE_KEY, uid);
    }
    
    public Long getAudBy(HttpServletRequest request) {
        return Long.valueOf(chaimMap(request).get("aud").asString());
    }
    public String accountByRequest(HttpServletRequest request) {
        DecodedJWT jwt;
        try {
            String token = getAuthToken(request);
            if (StringUtils.isEmpty(token)) {
                return "";
            }
            jwt = verify(token);
        } catch (Exception e) {
            return "";
        }
        return jwt.getSubject();
    }
    
    public Map<String, Claim> chaimMap(HttpServletRequest request) {
        return verify(getAuthToken(request)).getClaims();
    }
}


